package cn.edu.fzu.homemaking.helper;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

public class DateCycleHelper {

    private DateCycleHelper() {
    }

    public static class CycleInfo {

        private String startHour;

        private String endHour;

        public String getStartHour() {
            return startHour;
        }


        public void setStartHour(String startHour) {
            this.startHour = startHour;
        }


        public String getEndHour() {
            return endHour;
        }


        public void setEndHour(String endHour) {
            this.endHour = endHour;
        }


        public Integer getStartToHourInt() {
            if (StringUtils.isNotBlank(this.startHour)) {
                String tmp = StringUtils.substringBefore(this.startHour, ":");
                return NumberUtils.toInt(tmp);
            }
            return 0;
        }


        public Integer getStartToMinuteInt() {
            if (StringUtils.isNotBlank(this.startHour)) {
                String tmp = StringUtils.substringAfter(this.startHour, ":");
                return NumberUtils.toInt(tmp);
            }
            return 0;
        }


        public Integer getEndToHourInt() {
            if (StringUtils.isNotBlank(this.endHour)) {
                String tmp = StringUtils.substringBefore(this.endHour, ":");
                return NumberUtils.toInt(tmp);
            }
            return 0;
        }


        public Integer getEndToMinuteInt() {
            if (StringUtils.isNotBlank(this.endHour)) {
                String tmp = StringUtils.substringAfter(this.endHour, ":");
                return NumberUtils.toInt(tmp);
            }
            return 0;
        }

    }

    public static String beginEndToCircle(String begin, String end) {
        String beginTemp = StringUtils.substringBefore(begin, ":");
        String endTemp = StringUtils.substringBefore(end, ":");
        int start = NumberUtils.toInt(beginTemp) * 12;
        int parseInt = Integer.parseInt(StringUtils.substringAfter(begin, ":")) / 5;
        start += parseInt;

        int endTime = NumberUtils.toInt(endTemp) * 12;
        parseInt = Integer.parseInt(StringUtils.substringAfter(end, ":")) / 5;
        endTime += parseInt;

        BigInteger day = BigInteger.ZERO;
        for (int i = start; i < endTime; i++) {
            day = day.add(new BigInteger("1").shiftLeft(i));
        }
        return StringUtils.upperCase(addZeroForNum(day.toString(16), 72));
    }


    public static List<CycleInfo> circleToBeginEnd(String circle) {
        String dayHax = StringUtils.substring(circle, 0, 72);
        BigInteger bigInteger = new BigInteger(dayHax, 16);
        List<CycleInfo> list = new LinkedList<>();
        int begin = -1;
        int end = -1;
        for (int i = 0; i <= 288; i++) {
            BigInteger and = (bigInteger.shiftRight(i)).and(new BigInteger("1", 16));
            if ((begin == -1) && (and.longValue() > 0)) {
                begin = i;
            }
            if ((begin != -1) && and.longValue() <= 0) {
                end = i;
                list.add(buildCycle(begin, end));
                begin = -1;
            }
        }
        return list;
    }


    public static CycleInfo buildCycle(int begin, int end) {
        if (begin == -1) {
            begin = 0;
            end = 0;
        }
        CycleInfo cycle = new CycleInfo();
        cycle.setStartHour(String.format("%02d:%02d", begin / 12, (begin % 12) * 5));
        cycle.setEndHour(String.format("%02d:%02d", end / 12, (end % 12) * 5));
        return cycle;
    }


    public static String beginEndToCircleForOneMinute(String begin, String end) {
        String beginTemp = StringUtils.substringBefore(begin, ":");
        String endTemp = StringUtils.substringBefore(end, ":");
        int start = NumberUtils.toInt(beginTemp) * 60;
        int parseInt = Integer.parseInt(StringUtils.substringAfter(begin, ":"));
        start += parseInt;

        int endTime = NumberUtils.toInt(endTemp) * 60;
        parseInt = Integer.parseInt(StringUtils.substringAfter(end, ":"));
        endTime += parseInt;

        BigInteger day = BigInteger.ZERO;
        for (int i = start; i < endTime; i++) {
            day = day.add(new BigInteger("1").shiftLeft(i));
        }
        return StringUtils.upperCase(addZeroForNum(day.toString(16), 360));
    }


    public static List<CycleInfo> circleToBeginEndForOneMinute(String circle) {
        String dayHax = StringUtils.substring(circle, 0, 360);
        BigInteger bigInteger = new BigInteger(dayHax, 16);
        List<CycleInfo> list = new LinkedList<>();
        int begin = -1;
        int end = -1;
        for (int i = 0; i <= 1440; i++) {
            BigInteger and = (bigInteger.shiftRight(i)).and(new BigInteger("1", 16));
            if ((begin == -1) && (and.longValue() > 0)) {
                begin = i;
            }
            if ((begin != -1) && and.longValue() <= 0) {
                end = i;
                list.add(buildCycleForOneMinute(begin, end));
                begin = -1;
            }
        }
        return list;
    }


    public static CycleInfo buildCycleForOneMinute(int begin, int end) {
        if (begin == -1) {
            begin = 0;
            end = 0;
        }
        CycleInfo cycle = new CycleInfo();
        cycle.setStartHour(String.format("%02d:%02d", begin / 60, (begin % 60)));
        cycle.setEndHour(String.format("%02d:%02d", end / 60, (end % 60)));
        return cycle;
    }


    private static String addZeroForNum(String str, int strLength) {
        StringBuilder sb = new StringBuilder(str);
        if (sb.length() < strLength) {
            while (sb.length() < strLength) {
                sb.insert(0, "0");// 左补0
            }
        }
        return sb.toString();
    }


    public static String dateMergeForOneMinute(List<String> circles) {
        BigInteger time = new BigInteger("0", 16);
        for (String circle : circles) {
            time = time.or(new BigInteger(circle, 16));
        }
        return StringUtils.upperCase(addZeroForNum(time.toString(16), 360));
    }


    public static String dateMerge(List<String> circles) {
        BigInteger time = new BigInteger("0", 16);
        for (String circle : circles) {
            time = time.or(new BigInteger(circle, 16));
        }
        return StringUtils.upperCase(addZeroForNum(time.toString(16), 72));
    }


    /** 判断是否存在时间冲突 **/
    public static boolean dateConflict(String circle1, String circle2) {
        return !((new BigInteger(circle1, 16)).and(new BigInteger(circle2, 16))).equals(BigInteger.ZERO);
    }


    /** 去除circle1中包含的circle2时间区间 **/
    public static String getDiff(String circle1, String circle2) {
        BigInteger circle1Time = new BigInteger(circle1, 16);
        BigInteger sameTime = circle1Time.and(new BigInteger(circle2, 16));
        BigInteger diffTime = circle1Time.xor(sameTime);
        return StringUtils.upperCase(addZeroForNum(diffTime.toString(16), circle1.length()));
    }


    public static String getSame(String circle1, String circle2) {
        BigInteger sameTime = new BigInteger(circle1, 16).and(new BigInteger(circle2, 16));
        return StringUtils.upperCase(addZeroForNum(sameTime.toString(16), circle1.length()));
    }


    public static double getHour(String duration) {
        if (StringUtils.isBlank(duration)) {
            return 0d;
        }
        BigInteger time = new BigInteger(duration, 16);
        //判断time里面的二进制有多少个 1，一个1表示5分钟
        int count = 0;
        while (!time.equals(BigInteger.ZERO)) {
            time = time.and(time.subtract(BigInteger.valueOf(1L)));
            count++;
        }
        //一个小时有12个五分钟，故除以12可得小时数，保留精度为小数点后两位
        return BigDecimal.valueOf(count).divide(BigDecimal.valueOf(12), 2, RoundingMode.HALF_UP).doubleValue();
    }


    public static double getHourForOneMinute(String duration) {
        if (StringUtils.isBlank(duration)) {
            return 0d;
        }
        BigInteger time = new BigInteger(duration, 16);
        //判断time里面的二进制有多少个 1，一个1表示5分钟
        int count = 0;
        while (!time.equals(BigInteger.ZERO)) {
            time = time.and(time.subtract(BigInteger.valueOf(1L)));
            count++;
        }
        //一个小时有12个五分钟，故除以12可得小时数，保留精度为小数点后两位
        return BigDecimal.valueOf(count).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP).doubleValue();
    }

}
